const app = require('express').Router()
const gdal = require('gdal-async');
const proj4 = require('proj4')
const fs = require('fs');
// 处理队列
class RequestQueue {
  constructor(res) {
    this.arrayLength = 15
    this.queue = Array.from({
      length: this.arrayLength
    }, () => []);
    this.currentPointer = 0
    this.isProcessing = false;
    this.res = res
    this.startTime = new Date().getTime()
    this.resultArr = []
    this.clearArr = []
  }

  addRequest(name, option) {
    this.requestCount++
    this.queue[this.currentPointer].push({
      name: name,
      option: option
    })
    if (this.currentPointer == this.arrayLength - 1) {
      this.currentPointer = 0
    } else {
      this.currentPointer++
    }
    // this.queue.push({
    //   name: name,
    //   option: option
    // })
    // if (!this.isProcessing) {
    //   this.processQueue()
    // }
  }

  initiate() {
    for (let i = 0; i < this.arrayLength; i++) {
      this.processQueue(i);
    }
  }

  inspect() {
    if (this.clearArr.length == this.arrayLength) {
      let time = new Date().getTime()
      setTimeout(() => {
        this.res.send({
          data: this.resultArr,
          status: 200,
          duration: time - this.startTime,
          message: '全部转换完成'
        })
        return
      }, 1000)
    }
  }

  processQueue(num) {
    if (this.queue[num].length === 0) {
      this.clearArr.push(num)
      this.inspect()
      return
    }
    const {
      name,
      option
    } = this.queue[num].shift();
    this.projectToWGS84(name, option.inputPath, option.outputPath, num)
  }

  async projectToWGS84(name, inputPath, outputPath, num) {
    if (fs.existsSync(outputPath)) {
      this.resultArr.push({
        path: outputPath,
        status: 'exist'
      })
      console.log(outputPath + '已存在')
      this.processQueue(num)
      return
    }
    // 设置源图像和目标图像的路径
    const sourceImagePath = inputPath;
    const targetImagePath = outputPath;

    // 打开源图像
    const sourceDataset = gdal.open(sourceImagePath);

    // 获取源图像的投影和地理转换信息
    const sourceProjection = sourceDataset.srs;
    let noDataValue = sourceDataset.bands.get(1).noDataValue
    const dataType = sourceDataset.bands.get(1).dataType
    let sourceProj = sourceProjection.toProj4()
    const sourceGeoTransform = sourceDataset.geoTransform;
    let targetSrs = gdal.SpatialReference.fromProj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');
    let tx = new gdal.CoordinateTransformation(sourceProjection, targetSrs)
    // 获取目标图像地理转换信息
    let targetObject = this.getTargetGeoTransform(sourceGeoTransform, sourceDataset.rasterSize.x, sourceDataset.rasterSize.y, sourceProj, tx)
    // 创建目标图像
    const targetDataset = gdal.open(targetImagePath, 'w', 'GTiff',
      targetObject.dstWidth, targetObject.dstHeight, sourceDataset.bands.count(), dataType);
    // 设置目标图像的投影信息
    // targetDataset.srs = gdal.SpatialReference.fromEPSG(4549); // 例如，设置目标图像的投影为 EPSG 4326
    targetDataset.srs = targetSrs
    // 设置目标图像的地理转换信息
    targetDataset.geoTransform = targetObject.targetGeoTransform;
    targetDataset.bands.get(1).noDataValue = noDataValue
    // 进行图像投影转换
    // console.log('1')
    gdal.reprojectImageAsync({
      src: sourceDataset,
      dst: targetDataset,
      s_srs: sourceProjection,
      t_srs: targetDataset.srs
    }, (err) => {
      if (err) {
        console.error(`${name}图像投影转换失败：`, err);
        return;
      }
      console.error(`${name}图像投影转换成功：`);
      this.resultArr.push({
        path: outputPath,
        status: 'new'
      })
      // 关闭图像数据集
      sourceDataset.close();
      targetDataset.close();
      this.processQueue(num)
    });
  }
  getTargetGeoTransform(geoTransform, xSize, ySize, sourceProj, tx) {
    let xMin = geoTransform[0];
    let yMax = geoTransform[3];
    let w_src = geoTransform[1]; //像素宽度
    let h_src = geoTransform[5]; //像素⾼度
    let xMax = geoTransform[0] + xSize * w_src;
    let yMin = geoTransform[3] + ySize * h_src;
    let s_diagonal = new gdal.LineString()
    s_diagonal.points.add(yMax, xMin)
    s_diagonal.points.add(yMin, xMax)
    let t_diagonal = s_diagonal.clone()
    t_diagonal.transform(tx)
    let pixels_along_diagonal = Math.sqrt(xSize * xSize + ySize * ySize)
    let tr = t_diagonal.getLength() / pixels_along_diagonal
    let proj = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs';
    // let proj = '+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs';
    let transformCoordinate = proj4(sourceProj, proj);
    let a = transformCoordinate.forward([xMin, yMax]);
    let b = transformCoordinate.forward([xMax, yMax]);
    let c = transformCoordinate.forward([xMax, yMin]);
    let d = transformCoordinate.forward([xMin, yMin]);
    let dbX = [a[0], b[0], c[0], d[0]];
    let dbY = [a[1], b[1], c[1], d[1]];
    dbX.sort(function(a, b) {
      return a - b;
    })
    let dstXMin = dbX[0];
    let dstXMax = dbX[3];
    dbY.sort(function(a, b) {
      return a - b;
    })
    let dstYMin = dbY[0];
    let dstYMax = dbY[3];
    let targetGeoTransform = [];
    targetGeoTransform[0] = dstXMin;
    targetGeoTransform[3] = dstYMax;
    targetGeoTransform[1] = tr;
    targetGeoTransform[5] = -tr;
    targetGeoTransform[2] = geoTransform[2];
    targetGeoTransform[4] = geoTransform[4];
    let dstWidth = Math.ceil(Math.max(dstXMax - dstXMin) / tr);
    let dstHeight = Math.ceil(Math.max(dstYMax - dstYMin) / tr);
    return {
      targetGeoTransform,
      dstWidth,
      dstHeight
    }
  }
}

app.post('/projectToWGS84', (req, res) => {
  gdal.setPROJSearchPath(process.cwd() + "/assets/proj/data");
  let {
    inputPathArr
  } = req.body;
  // 创建请求队列实例
  const queue = new RequestQueue(res);
  let parentFile = ''
  pathArr = inputPathArr[0].split('\\')
  pathArr.forEach((item, index) => {
    if (index < pathArr.length - 1) {
      parentFile += item + '\\'
    }
  })
  let convertPath = parentFile + 'convert'
  if (!fs.existsSync(convertPath)) {
    fs.mkdirSync(convertPath);
  }
  inputPathArr.forEach((item, index) => {
    let arr = item.split('\\')
    let option = {
      inputPath: item,
      outputPath: convertPath + `\\${arr[arr.length - 1]}`
    }
    queue.addRequest(arr[arr.length - 1], option);
    if (index == inputPathArr.length - 1) {
      queue.initiate()
    }
  })
})

module.exports = app;